// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/compiler/backend/code-generator.h"
#include "src/compiler/backend/instruction-scheduler.h"

namespace v8 {
namespace internal {
    namespace compiler {

        bool InstructionScheduler::SchedulerSupported() { return true; }

        int InstructionScheduler::GetTargetInstructionFlags(
            const Instruction* instr) const
        {
            switch (instr->arch_opcode()) {
            case kMipsAbsD:
            case kMipsAbsS:
            case kMipsAdd:
            case kMipsAddD:
            case kMipsAddOvf:
            case kMipsAddPair:
            case kMipsAddS:
            case kMipsAnd:
            case kMipsByteSwap32:
            case kMipsCeilWD:
            case kMipsCeilWS:
            case kMipsClz:
            case kMipsCmp:
            case kMipsCmpD:
            case kMipsCmpS:
            case kMipsCtz:
            case kMipsCvtDS:
            case kMipsCvtDUw:
            case kMipsCvtDW:
            case kMipsCvtSD:
            case kMipsCvtSUw:
            case kMipsCvtSW:
            case kMipsDiv:
            case kMipsDivD:
            case kMipsDivS:
            case kMipsDivU:
            case kMipsExt:
            case kMipsF32x4Abs:
            case kMipsF32x4Add:
            case kMipsF32x4AddHoriz:
            case kMipsF32x4Eq:
            case kMipsF32x4ExtractLane:
            case kMipsF32x4Le:
            case kMipsF32x4Lt:
            case kMipsF32x4Max:
            case kMipsF32x4Min:
            case kMipsF32x4Mul:
            case kMipsF32x4Ne:
            case kMipsF32x4Neg:
            case kMipsF32x4RecipApprox:
            case kMipsF32x4RecipSqrtApprox:
            case kMipsF32x4ReplaceLane:
            case kMipsF32x4SConvertI32x4:
            case kMipsF32x4Splat:
            case kMipsF32x4Sub:
            case kMipsF32x4UConvertI32x4:
            case kMipsFloat32Max:
            case kMipsFloat32Min:
            case kMipsFloat32RoundDown:
            case kMipsFloat32RoundTiesEven:
            case kMipsFloat32RoundTruncate:
            case kMipsFloat32RoundUp:
            case kMipsFloat64ExtractHighWord32:
            case kMipsFloat64ExtractLowWord32:
            case kMipsFloat64InsertHighWord32:
            case kMipsFloat64InsertLowWord32:
            case kMipsFloat64Max:
            case kMipsFloat64Min:
            case kMipsFloat64RoundDown:
            case kMipsFloat64RoundTiesEven:
            case kMipsFloat64RoundTruncate:
            case kMipsFloat64RoundUp:
            case kMipsFloat64SilenceNaN:
            case kMipsFloorWD:
            case kMipsFloorWS:
            case kMipsI16x8Add:
            case kMipsI16x8AddHoriz:
            case kMipsI16x8AddSaturateS:
            case kMipsI16x8AddSaturateU:
            case kMipsI16x8Eq:
            case kMipsI16x8ExtractLane:
            case kMipsI16x8GeS:
            case kMipsI16x8GeU:
            case kMipsI16x8GtS:
            case kMipsI16x8GtU:
            case kMipsI16x8MaxS:
            case kMipsI16x8MaxU:
            case kMipsI16x8MinS:
            case kMipsI16x8MinU:
            case kMipsI16x8Mul:
            case kMipsI16x8Ne:
            case kMipsI16x8Neg:
            case kMipsI16x8ReplaceLane:
            case kMipsI16x8SConvertI32x4:
            case kMipsI16x8SConvertI8x16High:
            case kMipsI16x8SConvertI8x16Low:
            case kMipsI16x8Shl:
            case kMipsI16x8ShrS:
            case kMipsI16x8ShrU:
            case kMipsI16x8Splat:
            case kMipsI16x8Sub:
            case kMipsI16x8SubSaturateS:
            case kMipsI16x8SubSaturateU:
            case kMipsI16x8UConvertI32x4:
            case kMipsI16x8UConvertI8x16High:
            case kMipsI16x8UConvertI8x16Low:
            case kMipsI32x4Add:
            case kMipsI32x4AddHoriz:
            case kMipsI32x4Eq:
            case kMipsI32x4ExtractLane:
            case kMipsI32x4GeS:
            case kMipsI32x4GeU:
            case kMipsI32x4GtS:
            case kMipsI32x4GtU:
            case kMipsI32x4MaxS:
            case kMipsI32x4MaxU:
            case kMipsI32x4MinS:
            case kMipsI32x4MinU:
            case kMipsI32x4Mul:
            case kMipsI32x4Ne:
            case kMipsI32x4Neg:
            case kMipsI32x4ReplaceLane:
            case kMipsI32x4SConvertF32x4:
            case kMipsI32x4SConvertI16x8High:
            case kMipsI32x4SConvertI16x8Low:
            case kMipsI32x4Shl:
            case kMipsI32x4ShrS:
            case kMipsI32x4ShrU:
            case kMipsI32x4Splat:
            case kMipsI32x4Sub:
            case kMipsI32x4UConvertF32x4:
            case kMipsI32x4UConvertI16x8High:
            case kMipsI32x4UConvertI16x8Low:
            case kMipsI8x16Add:
            case kMipsI8x16AddSaturateS:
            case kMipsI8x16AddSaturateU:
            case kMipsI8x16Eq:
            case kMipsI8x16ExtractLane:
            case kMipsI8x16GeS:
            case kMipsI8x16GeU:
            case kMipsI8x16GtS:
            case kMipsI8x16GtU:
            case kMipsI8x16MaxS:
            case kMipsI8x16MaxU:
            case kMipsI8x16MinS:
            case kMipsI8x16MinU:
            case kMipsI8x16Mul:
            case kMipsI8x16Ne:
            case kMipsI8x16Neg:
            case kMipsI8x16ReplaceLane:
            case kMipsI8x16SConvertI16x8:
            case kMipsI8x16Shl:
            case kMipsI8x16ShrS:
            case kMipsI8x16ShrU:
            case kMipsI8x16Splat:
            case kMipsI8x16Sub:
            case kMipsI8x16SubSaturateS:
            case kMipsI8x16SubSaturateU:
            case kMipsI8x16UConvertI16x8:
            case kMipsIns:
            case kMipsLsa:
            case kMipsMaddD:
            case kMipsMaddS:
            case kMipsMaxD:
            case kMipsMaxS:
            case kMipsMinD:
            case kMipsMinS:
            case kMipsMod:
            case kMipsModU:
            case kMipsMov:
            case kMipsMsubD:
            case kMipsMsubS:
            case kMipsMul:
            case kMipsMulD:
            case kMipsMulHigh:
            case kMipsMulHighU:
            case kMipsMulOvf:
            case kMipsMulPair:
            case kMipsMulS:
            case kMipsNegD:
            case kMipsNegS:
            case kMipsNor:
            case kMipsOr:
            case kMipsPopcnt:
            case kMipsRor:
            case kMipsRoundWD:
            case kMipsRoundWS:
            case kMipsS128And:
            case kMipsS128Not:
            case kMipsS128Or:
            case kMipsS128Select:
            case kMipsS128Xor:
            case kMipsS128Zero:
            case kMipsS16x2Reverse:
            case kMipsS16x4Reverse:
            case kMipsS16x8InterleaveEven:
            case kMipsS16x8InterleaveLeft:
            case kMipsS16x8InterleaveOdd:
            case kMipsS16x8InterleaveRight:
            case kMipsS16x8PackEven:
            case kMipsS16x8PackOdd:
            case kMipsS1x16AllTrue:
            case kMipsS1x16AnyTrue:
            case kMipsS1x4AllTrue:
            case kMipsS1x4AnyTrue:
            case kMipsS1x8AllTrue:
            case kMipsS1x8AnyTrue:
            case kMipsS32x4InterleaveEven:
            case kMipsS32x4InterleaveLeft:
            case kMipsS32x4InterleaveOdd:
            case kMipsS32x4InterleaveRight:
            case kMipsS32x4PackEven:
            case kMipsS32x4PackOdd:
            case kMipsS32x4Shuffle:
            case kMipsS8x16Concat:
            case kMipsS8x16InterleaveEven:
            case kMipsS8x16InterleaveLeft:
            case kMipsS8x16InterleaveOdd:
            case kMipsS8x16InterleaveRight:
            case kMipsS8x16PackEven:
            case kMipsS8x16PackOdd:
            case kMipsS8x16Shuffle:
            case kMipsS8x2Reverse:
            case kMipsS8x4Reverse:
            case kMipsS8x8Reverse:
            case kMipsSar:
            case kMipsSarPair:
            case kMipsSeb:
            case kMipsSeh:
            case kMipsShl:
            case kMipsShlPair:
            case kMipsShr:
            case kMipsShrPair:
            case kMipsSqrtD:
            case kMipsSqrtS:
            case kMipsSub:
            case kMipsSubD:
            case kMipsSubOvf:
            case kMipsSubPair:
            case kMipsSubS:
            case kMipsTruncUwD:
            case kMipsTruncUwS:
            case kMipsTruncWD:
            case kMipsTruncWS:
            case kMipsTst:
            case kMipsXor:
                return kNoOpcodeFlags;

            case kMipsLb:
            case kMipsLbu:
            case kMipsLdc1:
            case kMipsLh:
            case kMipsLhu:
            case kMipsLw:
            case kMipsLwc1:
            case kMipsMsaLd:
            case kMipsPeek:
            case kMipsUldc1:
            case kMipsUlh:
            case kMipsUlhu:
            case kMipsUlw:
            case kMipsUlwc1:
            case kMipsWord32AtomicPairLoad:
                return kIsLoadOperation;

            case kMipsModD:
            case kMipsModS:
            case kMipsMsaSt:
            case kMipsPush:
            case kMipsSb:
            case kMipsSdc1:
            case kMipsSh:
            case kMipsStackClaim:
            case kMipsStoreToStackSlot:
            case kMipsSw:
            case kMipsSwc1:
            case kMipsUsdc1:
            case kMipsUsh:
            case kMipsUsw:
            case kMipsUswc1:
            case kMipsWord32AtomicPairStore:
            case kMipsWord32AtomicPairAdd:
            case kMipsWord32AtomicPairSub:
            case kMipsWord32AtomicPairAnd:
            case kMipsWord32AtomicPairOr:
            case kMipsWord32AtomicPairXor:
            case kMipsWord32AtomicPairExchange:
            case kMipsWord32AtomicPairCompareExchange:
                return kHasSideEffect;

#define CASE(Name) case k##Name:
                COMMON_ARCH_OPCODE_LIST(CASE)
#undef CASE
                // Already covered in architecture independent code.
                UNREACHABLE();
            }

            UNREACHABLE();
        }

        enum Latency {
            BRANCH = 4, // Estimated max.
            RINT_S = 4, // Estimated.
            RINT_D = 4, // Estimated.

            MULT = 4,
            MULTU = 4,
            MADD = 4,
            MADDU = 4,
            MSUB = 4,
            MSUBU = 4,

            MUL = 7,
            MULU = 7,
            MUH = 7,
            MUHU = 7,

            DIV = 50, // Min:11 Max:50
            DIVU = 50,

            ABS_S = 4,
            ABS_D = 4,
            NEG_S = 4,
            NEG_D = 4,
            ADD_S = 4,
            ADD_D = 4,
            SUB_S = 4,
            SUB_D = 4,
            MAX_S = 4, // Estimated.
            MAX_D = 4, // Estimated.
            C_cond_S = 4,
            C_cond_D = 4,
            MUL_S = 4,

            MADD_S = 4,
            MSUB_S = 4,
            NMADD_S = 4,
            NMSUB_S = 4,

            CABS_cond_S = 4,
            CABS_cond_D = 4,

            CVT_D_S = 4,
            CVT_PS_PW = 4,

            CVT_S_W = 4,
            CVT_S_L = 4,
            CVT_D_W = 4,
            CVT_D_L = 4,

            CVT_S_D = 4,

            CVT_W_S = 4,
            CVT_W_D = 4,
            CVT_L_S = 4,
            CVT_L_D = 4,

            CEIL_W_S = 4,
            CEIL_W_D = 4,
            CEIL_L_S = 4,
            CEIL_L_D = 4,

            FLOOR_W_S = 4,
            FLOOR_W_D = 4,
            FLOOR_L_S = 4,
            FLOOR_L_D = 4,

            ROUND_W_S = 4,
            ROUND_W_D = 4,
            ROUND_L_S = 4,
            ROUND_L_D = 4,

            TRUNC_W_S = 4,
            TRUNC_W_D = 4,
            TRUNC_L_S = 4,
            TRUNC_L_D = 4,

            MOV_S = 4,
            MOV_D = 4,

            MOVF_S = 4,
            MOVF_D = 4,

            MOVN_S = 4,
            MOVN_D = 4,

            MOVT_S = 4,
            MOVT_D = 4,

            MOVZ_S = 4,
            MOVZ_D = 4,

            MUL_D = 5,
            MADD_D = 5,
            MSUB_D = 5,
            NMADD_D = 5,
            NMSUB_D = 5,

            RECIP_S = 13,
            RECIP_D = 26,

            RSQRT_S = 17,
            RSQRT_D = 36,

            DIV_S = 17,
            SQRT_S = 17,

            DIV_D = 32,
            SQRT_D = 32,

            MTC1 = 4,
            MTHC1 = 4,
            DMTC1 = 4,
            LWC1 = 4,
            LDC1 = 4,
            LDXC1 = 4,
            LUXC1 = 4,
            LWXC1 = 4,

            MFC1 = 1,
            MFHC1 = 1,
            MFHI = 1,
            MFLO = 1,
            DMFC1 = 1,
            SWC1 = 1,
            SDC1 = 1,
            SDXC1 = 1,
            SUXC1 = 1,
            SWXC1 = 1,
        };

        int ClzLatency()
        {
            if (IsMipsArchVariant(kLoongson)) {
                return (6 + 2 * Latency::BRANCH);
            } else {
                return 1;
            }
        }

        int RorLatency(bool is_operand_register = true)
        {
            if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
                return 1;
            } else {
                if (is_operand_register) {
                    return 4;
                } else {
                    return 3; // Estimated max.
                }
            }
        }

        int AdduLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                return 1;
            } else {
                return 2; // Estimated max.
            }
        }

        int XorLatency(bool is_operand_register = true)
        {
            return AdduLatency(is_operand_register);
        }

        int AndLatency(bool is_operand_register = true)
        {
            return AdduLatency(is_operand_register);
        }

        int OrLatency(bool is_operand_register = true)
        {
            return AdduLatency(is_operand_register);
        }

        int SubuLatency(bool is_operand_register = true)
        {
            return AdduLatency(is_operand_register);
        }

        int MulLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                if (IsMipsArchVariant(kLoongson)) {
                    return Latency::MULT + 1;
                } else {
                    return Latency::MUL + 1;
                }
            } else {
                if (IsMipsArchVariant(kLoongson)) {
                    return Latency::MULT + 2;
                } else {
                    return Latency::MUL + 2;
                }
            }
        }

        int NorLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                return 1;
            } else {
                return 2;
            }
        }

        int InsLatency()
        {
            if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
                return 1;
            } else {
                return SubuLatency(false) + 7;
            }
        }

        int ShlPairLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                int latency = AndLatency(false) + NorLatency() + OrLatency() + AndLatency(false) + 4;
                if (IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r6)) {
                    return latency + Latency::BRANCH + 2;
                } else {
                    return latency + 2;
                }
            } else {
                return 2;
            }
        }

        int ShrPairLatency(bool is_operand_register = true, uint32_t shift = 0)
        {
            if (is_operand_register) {
                int latency = AndLatency(false) + NorLatency() + OrLatency() + AndLatency(false) + 4;
                if (IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r6)) {
                    return latency + Latency::BRANCH + 2;
                } else {
                    return latency + 2;
                }
            } else {
                // Estimated max.
                return (InsLatency() + 2 > OrLatency() + 3) ? InsLatency() + 2
                                                            : OrLatency() + 3;
            }
        }

        int SarPairLatency(bool is_operand_register = true, uint32_t shift = 0)
        {
            if (is_operand_register) {
                return AndLatency(false) + NorLatency() + OrLatency() + AndLatency(false) + Latency::BRANCH + 6;
            } else {
                shift = shift & 0x3F;
                if (shift == 0) {
                    return 2;
                } else if (shift < 32) {
                    if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
                        return InsLatency() + 2;
                    } else {
                        return OrLatency() + 3;
                    }
                } else if (shift == 32) {
                    return 2;
                } else {
                    return 2;
                }
            }
        }

        int ExtLatency()
        {
            if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
                return 1;
            } else {
                // Estimated max.
                return 2;
            }
        }

        int LsaLatency()
        {
            // Estimated max.
            return AdduLatency() + 1;
        }

        int SltLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                return 1;
            } else {
                return 2; // Estimated max.
            }
        }

        int SltuLatency(bool is_operand_register = true)
        {
            return SltLatency(is_operand_register);
        }

        int AddPairLatency() { return 3 * AdduLatency() + SltLatency(); }

        int SubPairLatency() { return SltuLatency() + 3 * SubuLatency(); }

        int MuluLatency(bool is_operand_register = true)
        {
            int latency = 0;
            if (!is_operand_register)
                latency++;
            if (!IsMipsArchVariant(kMips32r6)) {
                return latency + Latency::MULTU + 2;
            } else {
                return latency + Latency::MULU + Latency::MUHU;
            }
        }

        int MulPairLatency()
        {
            return MuluLatency() + 2 * MulLatency() + 2 * AdduLatency();
        }

        int MaddSLatency()
        {
            if (IsMipsArchVariant(kMips32r2)) {
                return Latency::MADD_D;
            } else {
                return Latency::MUL_D + Latency::ADD_D;
            }
        }

        int MaddDLatency()
        {
            if (IsMipsArchVariant(kMips32r2)) {
                return Latency::MADD_D;
            } else {
                return Latency::MUL_D + Latency::ADD_D;
            }
        }

        int MsubSLatency()
        {
            if (IsMipsArchVariant(kMips32r2)) {
                return Latency::MSUB_S;
            } else {
                return Latency::MUL_S + Latency::SUB_S;
            }
        }

        int MsubDLatency()
        {
            if (IsMipsArchVariant(kMips32r2)) {
                return Latency::MSUB_D;
            } else {
                return Latency::MUL_D + Latency::SUB_D;
            }
        }

        int Mfhc1Latency()
        {
            if (IsFp32Mode()) {
                return Latency::MFC1;
            } else {
                return 1;
            }
        }

        int Mthc1Latency()
        {
            if (IsFp32Mode()) {
                return Latency::MTC1;
            } else {
                return 1;
            }
        }

        int MoveLatency(bool is_double_register = true)
        {
            if (!is_double_register) {
                return Latency::MTC1 + 1;
            } else {
                return Mthc1Latency() + 1; // Estimated.
            }
        }

        int Float64RoundLatency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return Latency::RINT_D + 4;
            } else {
                // For ceil_l_d, floor_l_d, round_l_d, trunc_l_d latency is 4.
                return Mfhc1Latency() + ExtLatency() + Latency::BRANCH + Latency::MOV_D + 4 + MoveLatency() + 1 + Latency::BRANCH + Latency::CVT_D_L;
            }
        }

        int Float32RoundLatency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return Latency::RINT_S + 4;
            } else {
                // For ceil_w_s, floor_w_s, round_w_s, trunc_w_s latency is 4.
                return Latency::MFC1 + ExtLatency() + Latency::BRANCH + Latency::MOV_S + 4 + Latency::MFC1 + Latency::BRANCH + Latency::CVT_S_W;
            }
        }

        int CvtDUwLatency()
        {
            if (IsFp64Mode()) {
                return Latency::MTC1 + Mthc1Latency() + Latency::CVT_D_L;
            } else {
                return Latency::BRANCH + Latency::MTC1 + 1 + Latency::MTC1 + Mthc1Latency() + Latency::CVT_D_W + Latency::BRANCH + Latency::ADD_D + Latency::CVT_D_W;
            }
        }

        int CvtSUwLatency() { return CvtDUwLatency() + Latency::CVT_S_D; }

        int Floor_w_dLatency()
        {
            if (IsMipsArchVariant(kLoongson)) {
                return Mfhc1Latency() + Latency::FLOOR_W_D + Mthc1Latency();
            } else {
                return Latency::FLOOR_W_D;
            }
        }

        int FloorWDLatency() { return Floor_w_dLatency() + Latency::MFC1; }

        int Ceil_w_dLatency()
        {
            if (IsMipsArchVariant(kLoongson)) {
                return Mfhc1Latency() + Latency::CEIL_W_D + Mthc1Latency();
            } else {
                return Latency::CEIL_W_D;
            }
        }

        int CeilWDLatency() { return Ceil_w_dLatency() + Latency::MFC1; }

        int Round_w_dLatency()
        {
            if (IsMipsArchVariant(kLoongson)) {
                return Mfhc1Latency() + Latency::ROUND_W_D + Mthc1Latency();
            } else {
                return Latency::ROUND_W_D;
            }
        }

        int RoundWDLatency() { return Round_w_dLatency() + Latency::MFC1; }

        int Trunc_w_dLatency()
        {
            if (IsMipsArchVariant(kLoongson)) {
                return Mfhc1Latency() + Latency::TRUNC_W_D + Mthc1Latency();
            } else {
                return Latency::TRUNC_W_D;
            }
        }

        int MovnLatency()
        {
            if (IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r6)) {
                return Latency::BRANCH + 1;
            } else {
                return 1;
            }
        }

        int Trunc_uw_dLatency()
        {
            return 1 + Latency::MTC1 + Mthc1Latency() + Latency::BRANCH + Latency::SUB_D + Latency::TRUNC_W_D + Latency::MFC1 + OrLatency(false) + Latency::BRANCH + Latency::TRUNC_W_D + Latency::MFC1;
        }

        int Trunc_uw_sLatency()
        {
            return 1 + Latency::MTC1 + Latency::BRANCH + Latency::SUB_S + Latency::TRUNC_W_S + Latency::MFC1 + OrLatency(false) + Latency::TRUNC_W_S + Latency::MFC1;
        }

        int MovzLatency()
        {
            if (IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r6)) {
                return Latency::BRANCH + 1;
            } else {
                return 1;
            }
        }

        int FmoveLowLatency()
        {
            if (IsFp32Mode()) {
                return Latency::MTC1;
            } else {
                return Latency::MFHC1 + Latency::MTC1 + Latency::MTHC1;
            }
        }

        int SebLatency()
        {
            if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
                return 1;
            } else {
                return 2;
            }
        }

        int SehLatency()
        {
            if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
                return 1;
            } else {
                return 2;
            }
        }

        int UlhuLatency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return 1;
            } else {
                return 4;
            }
        }

        int UlhLatency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return 1;
            } else {
                return 4;
            }
        }

        int AdjustBaseAndOffsetLatency()
        {
            return 3; // Estimated max.
        }

        int UshLatency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return 1;
            } else {
                return AdjustBaseAndOffsetLatency() + 4; // Estimated max.
            }
        }

        int UlwLatency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return 1;
            } else {
                return AdjustBaseAndOffsetLatency() + 3; // Estimated max.
            }
        }

        int UswLatency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return 1;
            } else {
                return AdjustBaseAndOffsetLatency() + 2;
            }
        }

        int Ulwc1Latency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return Latency::LWC1;
            } else {
                return UlwLatency() + Latency::MTC1;
            }
        }

        int Uswc1Latency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return Latency::SWC1;
            } else {
                return Latency::MFC1 + UswLatency();
            }
        }

        int Ldc1Latency()
        {
            int latency = AdjustBaseAndOffsetLatency() + Latency::LWC1;
            if (IsFp32Mode()) {
                return latency + Latency::LWC1;
            } else {
                return latency + 1 + Mthc1Latency();
            }
        }

        int Uldc1Latency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return Ldc1Latency();
            } else {
                return 2 * UlwLatency() + Latency::MTC1 + Mthc1Latency();
            }
        }

        int Sdc1Latency()
        {
            int latency = AdjustBaseAndOffsetLatency() + Latency::SWC1;
            if (IsFp32Mode()) {
                return latency + Latency::SWC1;
            } else {
                return latency + Mfhc1Latency() + 1;
            }
        }

        int Usdc1Latency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return Sdc1Latency();
            } else {
                return Latency::MFC1 + 2 * UswLatency() + Mfhc1Latency();
            }
        }

        int PushRegisterLatency() { return AdduLatency(false) + 1; }

        int ByteSwapSignedLatency()
        {
            // operand_size == 4
            if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
                return 2;
            } else if (IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kLoongson)) {
                return 10;
            }
        }

        int LlLatency(int offset)
        {
            bool is_one_instruction = IsMipsArchVariant(kMips32r6) ? is_int9(offset) : is_int16(offset);
            if (is_one_instruction) {
                return 1;
            } else {
                return 3;
            }
        }

        int ExtractBitsLatency(int size, bool sign_extend)
        {
            int latency = 1 + ExtLatency();
            if (size == 8) {
                if (sign_extend) {
                    return latency + SebLatency();
                } else {
                    return 0;
                }
            } else if (size == 16) {
                if (sign_extend) {
                    return latency + SehLatency();
                } else {
                    return 0;
                }
            } else {
                UNREACHABLE();
            }
        }

        int NegLatency() { return 1; }

        int InsertBitsLatency()
        {
            return RorLatency() + InsLatency() + SubuLatency(false) + NegLatency() + RorLatency();
        }

        int ScLatency(int offset)
        {
            bool is_one_instruction = IsMipsArchVariant(kMips32r6) ? is_int9(offset) : is_int16(offset);
            if (is_one_instruction) {
                return 1;
            } else {
                return 3;
            }
        }

        int BranchShortHelperR6Latency()
        {
            return 2; // Estimated max.
        }

        int BranchShortHelperLatency()
        {
            return SltLatency() + 2; // Estimated max.
        }

        int BranchShortLatency(BranchDelaySlot bdslot = PROTECT)
        {
            if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) {
                return BranchShortHelperR6Latency();
            } else {
                return BranchShortHelperLatency();
            }
        }

        int Word32AtomicExchangeLatency(bool sign_extend, int size)
        {
            return AdduLatency() + 1 + SubuLatency() + 2 + LlLatency(0) + ExtractBitsLatency(size, sign_extend) + InsertBitsLatency() + ScLatency(0) + BranchShortLatency() + 1;
        }

        int Word32AtomicCompareExchangeLatency(bool sign_extend, int size)
        {
            return AdduLatency() + 1 + SubuLatency() + 2 + LlLatency(0) + ExtractBitsLatency(size, sign_extend) + BranchShortLatency() + 1;
        }

        int AddOverflowLatency()
        {
            return 6; // Estimated max.
        }

        int SubOverflowLatency()
        {
            return 6; // Estimated max.
        }

        int MulhLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                if (!IsMipsArchVariant(kMips32r6)) {
                    return Latency::MULT + Latency::MFHI;
                } else {
                    return Latency::MUH;
                }
            } else {
                if (!IsMipsArchVariant(kMips32r6)) {
                    return 1 + Latency::MULT + Latency::MFHI;
                } else {
                    return 1 + Latency::MUH;
                }
            }
        }

        int MulhuLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                if (!IsMipsArchVariant(kMips32r6)) {
                    return Latency::MULTU + Latency::MFHI;
                } else {
                    return Latency::MUHU;
                }
            } else {
                if (!IsMipsArchVariant(kMips32r6)) {
                    return 1 + Latency::MULTU + Latency::MFHI;
                } else {
                    return 1 + Latency::MUHU;
                }
            }
        }

        int MulOverflowLatency()
        {
            return MulLatency() + 4; // Estimated max.
        }

        int ModLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                if (!IsMipsArchVariant(kMips32r6)) {
                    return Latency::DIV + Latency::MFHI;
                } else {
                    return 1;
                }
            } else {
                if (!IsMipsArchVariant(kMips32r6)) {
                    return 1 + Latency::DIV + Latency::MFHI;
                } else {
                    return 2;
                }
            }
        }

        int ModuLatency(bool is_operand_register = true)
        {
            return ModLatency(is_operand_register);
        }

        int DivLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                if (!IsMipsArchVariant(kMips32r6)) {
                    return Latency::DIV + Latency::MFLO;
                } else {
                    return Latency::DIV;
                }
            } else {
                if (!IsMipsArchVariant(kMips32r6)) {
                    return 1 + Latency::DIV + Latency::MFLO;
                } else {
                    return 1 + Latency::DIV;
                }
            }
        }

        int DivuLatency(bool is_operand_register = true)
        {
            if (is_operand_register) {
                if (!IsMipsArchVariant(kMips32r6)) {
                    return Latency::DIVU + Latency::MFLO;
                } else {
                    return Latency::DIVU;
                }
            } else {
                if (!IsMipsArchVariant(kMips32r6)) {
                    return 1 + Latency::DIVU + Latency::MFLO;
                } else {
                    return 1 + Latency::DIVU;
                }
            }
        }

        int CtzLatency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return RorLatency(false) + 2 + ClzLatency();
            } else {
                return AdduLatency(false) + XorLatency() + AndLatency() + ClzLatency() + 1 + SubuLatency();
            }
        }

        int PopcntLatency()
        {
            return 4 * AndLatency() + SubuLatency() + 2 * AdduLatency() + MulLatency() + 8;
        }

        int CompareFLatency() { return Latency::C_cond_S; }

        int CompareIsNanFLatency() { return CompareFLatency(); }

        int CompareIsNanF32Latency() { return CompareIsNanFLatency(); }

        int Neg_sLatency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return Latency::NEG_S;
            } else {
                // Estimated.
                return CompareIsNanF32Latency() + 2 * Latency::BRANCH + Latency::NEG_S + Latency::MFC1 + 1 + XorLatency() + Latency::MTC1;
            }
        }

        int CompareIsNanF64Latency() { return CompareIsNanFLatency(); }

        int Neg_dLatency()
        {
            if (IsMipsArchVariant(kMips32r6)) {
                return Latency::NEG_D;
            } else {
                // Estimated.
                return CompareIsNanF64Latency() + 2 * Latency::BRANCH + Latency::NEG_D + Mfhc1Latency() + 1 + XorLatency() + Mthc1Latency();
            }
        }

        int CompareF32Latency() { return CompareFLatency(); }

        int Move_sLatency()
        {
            return Latency::MOV_S; // Estimated max.
        }

        int Float32MaxLatency()
        {
            // Estimated max.
            int latency = CompareIsNanF32Latency() + Latency::BRANCH;
            if (IsMipsArchVariant(kMips32r6)) {
                return latency + Latency::MAX_S;
            } else {
                return latency + 5 * Latency::BRANCH + 2 * CompareF32Latency() + Latency::MFC1 + Move_sLatency();
            }
        }

        int CompareF64Latency() { return CompareF32Latency(); }

        int Move_dLatency()
        {
            return Latency::MOV_D; // Estimated max.
        }

        int Float64MaxLatency()
        {
            // Estimated max.
            int latency = CompareIsNanF64Latency() + Latency::BRANCH;
            if (IsMipsArchVariant(kMips32r6)) {
                return latency + Latency::MAX_D;
            } else {
                return latency + 5 * Latency::BRANCH + 2 * CompareF64Latency() + Latency::MFHC1 + 2 * Move_dLatency();
            }
        }

        int PrepareCallCFunctionLatency()
        {
            int frame_alignment = TurboAssembler::ActivationFrameAlignment();
            if (frame_alignment > kSystemPointerSize) {
                return 1 + SubuLatency(false) + AndLatency(false) + 1;
            } else {
                return SubuLatency(false);
            }
        }

        int MovToFloatParametersLatency() { return 2 * MoveLatency(); }

        int CallLatency()
        {
            // Estimated.
            return AdduLatency(false) + Latency::BRANCH + 3;
        }

        int CallCFunctionHelperLatency()
        {
            // Estimated.
            int latency = AndLatency(false) + Latency::BRANCH + 2 + CallLatency();
            if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
                latency++;
            } else {
                latency += AdduLatency(false);
            }
            return latency;
        }

        int CallCFunctionLatency() { return 1 + CallCFunctionHelperLatency(); }

        int MovFromFloatResultLatency() { return MoveLatency(); }

        int Float32MinLatency()
        {
            // Estimated max.
            return CompareIsNanF32Latency() + Latency::BRANCH + 2 * (CompareF32Latency() + Latency::BRANCH) + Latency::MFC1 + 2 * Latency::BRANCH + Move_sLatency();
        }

        int Float64MinLatency()
        {
            // Estimated max.
            return CompareIsNanF64Latency() + Latency::BRANCH + 2 * (CompareF64Latency() + Latency::BRANCH) + Mfhc1Latency() + 2 * Latency::BRANCH + Move_dLatency();
        }

        int SmiUntagLatency() { return 1; }

        int PrepareForTailCallLatency()
        {
            // Estimated max.
            return 2 * (LsaLatency() + AdduLatency(false)) + 2 + Latency::BRANCH + Latency::BRANCH + 2 * SubuLatency(false) + 2 + Latency::BRANCH + 1;
        }

        int AssemblePopArgumentsAdaptorFrameLatency()
        {
            return 1 + Latency::BRANCH + 1 + SmiUntagLatency() + PrepareForTailCallLatency();
        }

        int JumpLatency()
        {
            // Estimated max.
            return 1 + AdduLatency(false) + Latency::BRANCH + 2;
        }

        int AssertLatency() { return 1; }

        int MultiPushLatency()
        {
            int latency = SubuLatency(false);
            for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
                latency++;
            }
            return latency;
        }

        int MultiPushFPULatency()
        {
            int latency = SubuLatency(false);
            for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
                latency += Sdc1Latency();
            }
            return latency;
        }

        int PushCallerSavedLatency(SaveFPRegsMode fp_mode)
        {
            int latency = MultiPushLatency();
            if (fp_mode == kSaveFPRegs) {
                latency += MultiPushFPULatency();
            }
            return latency;
        }

        int MultiPopFPULatency()
        {
            int latency = 0;
            for (int16_t i = 0; i < kNumRegisters; i++) {
                latency += Ldc1Latency();
            }
            return latency++;
        }

        int MultiPopLatency()
        {
            int latency = 0;
            for (int16_t i = 0; i < kNumRegisters; i++) {
                latency++;
            }
            return latency++;
        }

        int PopCallerSavedLatency(SaveFPRegsMode fp_mode)
        {
            int latency = 0;
            if (fp_mode == kSaveFPRegs) {
                latency += MultiPopFPULatency();
            }
            return latency + MultiPopLatency();
        }

        int AssembleArchJumpLatency()
        {
            // Estimated max.
            return Latency::BRANCH;
        }

        int AssembleArchLookupSwitchLatency(int cases)
        {
            return cases * (1 + Latency::BRANCH) + AssembleArchJumpLatency();
        }

        int AssembleArchBinarySearchSwitchLatency(int cases)
        {
            if (cases < CodeGenerator::kBinarySearchSwitchMinimalCases) {
                return AssembleArchLookupSwitchLatency(cases);
            }
            return 1 + Latency::BRANCH + AssembleArchBinarySearchSwitchLatency(cases / 2);
        }

        int GenerateSwitchTableLatency()
        {
            int latency = 0;
            if (kArchVariant >= kMips32r6) {
                latency = LsaLatency() + 2;
            } else {
                latency = 6;
            }
            latency += 2;
            return latency;
        }

        int AssembleArchTableSwitchLatency()
        {
            return Latency::BRANCH + GenerateSwitchTableLatency();
        }

        int AssembleReturnLatency()
        {
            // Estimated max.
            return AdduLatency(false) + MultiPopLatency() + MultiPopFPULatency() + Latency::BRANCH + 1 + AdduLatency() + 8;
        }

        int TryInlineTruncateDoubleToILatency()
        {
            return 2 + Latency::TRUNC_W_D + Latency::MFC1 + 2 + AndLatency(false) + Latency::BRANCH;
        }

        int CallStubDelayedLatency() { return 1 + CallLatency(); }

        int TruncateDoubleToIDelayedLatency()
        {
            // TODO(mips): This no longer reflects how TruncateDoubleToI is called.
            return TryInlineTruncateDoubleToILatency() + 1 + SubuLatency(false) + Sdc1Latency() + CallStubDelayedLatency() + AdduLatency(false) + 1;
        }

        int CheckPageFlagLatency()
        {
            return 2 * AndLatency(false) + 1 + Latency::BRANCH;
        }

        int InstructionScheduler::GetInstructionLatency(const Instruction* instr)
        {
            // Basic latency modeling for MIPS32 instructions. They have been determined
            // in an empirical way.
            switch (instr->arch_opcode()) {
            case kArchCallCodeObject:
            case kArchCallWasmFunction:
                return CallLatency();
            case kArchTailCallCodeObjectFromJSFunction:
            case kArchTailCallCodeObject: {
                int latency = 0;
                if (instr->arch_opcode() == kArchTailCallCodeObjectFromJSFunction) {
                    latency = AssemblePopArgumentsAdaptorFrameLatency();
                }
                return latency + JumpLatency();
            }
            case kArchTailCallWasm:
            case kArchTailCallAddress:
                return JumpLatency();
            case kArchCallJSFunction: {
                int latency = 0;
                if (FLAG_debug_code) {
                    latency = 1 + AssertLatency();
                }
                return latency + 1 + AdduLatency(false) + CallLatency();
            }
            case kArchPrepareCallCFunction:
                return PrepareCallCFunctionLatency();
            case kArchSaveCallerRegisters: {
                auto fp_mode = static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
                return PushCallerSavedLatency(fp_mode);
            }
            case kArchRestoreCallerRegisters: {
                auto fp_mode = static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
                return PopCallerSavedLatency(fp_mode);
            }
            case kArchPrepareTailCall:
                return 2; // Estimated max.
            case kArchCallCFunction:
                return CallCFunctionLatency();
            case kArchJmp:
                return AssembleArchJumpLatency();
            case kArchBinarySearchSwitch:
                return AssembleArchBinarySearchSwitchLatency((instr->InputCount() - 2) / 2);
            case kArchLookupSwitch:
                return AssembleArchLookupSwitchLatency((instr->InputCount() - 2) / 2);
            case kArchTableSwitch:
                return AssembleArchTableSwitchLatency();
            case kArchDebugAbort:
                return CallLatency() + 1;
            case kArchComment:
            case kArchDeoptimize:
                return 0;
            case kArchRet:
                return AssembleReturnLatency();
            case kArchTruncateDoubleToI:
                return TruncateDoubleToIDelayedLatency();
            case kArchStoreWithWriteBarrier:
                return AdduLatency() + 1 + CheckPageFlagLatency();
            case kArchStackSlot: {
                // Estimated max.
                return AdduLatency(false) + AndLatency(false) + AssertLatency() + AdduLatency(false) + AndLatency(false) + BranchShortLatency() + 1 + SubuLatency() + AdduLatency();
            }
            case kArchWordPoisonOnSpeculation:
                return AndLatency();
            case kIeee754Float64Acos:
            case kIeee754Float64Acosh:
            case kIeee754Float64Asin:
            case kIeee754Float64Asinh:
            case kIeee754Float64Atan:
            case kIeee754Float64Atanh:
            case kIeee754Float64Atan2:
            case kIeee754Float64Cos:
            case kIeee754Float64Cosh:
            case kIeee754Float64Cbrt:
            case kIeee754Float64Exp:
            case kIeee754Float64Expm1:
            case kIeee754Float64Log:
            case kIeee754Float64Log1p:
            case kIeee754Float64Log10:
            case kIeee754Float64Log2:
            case kIeee754Float64Pow:
            case kIeee754Float64Sin:
            case kIeee754Float64Sinh:
            case kIeee754Float64Tan:
            case kIeee754Float64Tanh:
                return PrepareCallCFunctionLatency() + MovToFloatParametersLatency() + CallCFunctionLatency() + MovFromFloatResultLatency();
            case kMipsAdd:
                return AdduLatency(instr->InputAt(1)->IsRegister());
            case kMipsAnd:
                return AndLatency(instr->InputAt(1)->IsRegister());
            case kMipsOr:
                return OrLatency(instr->InputAt(1)->IsRegister());
            case kMipsXor:
                return XorLatency(instr->InputAt(1)->IsRegister());
            case kMipsSub:
                return SubuLatency(instr->InputAt(1)->IsRegister());
            case kMipsNor:
                return NorLatency(instr->InputAt(1)->IsRegister());
            case kMipsAddOvf:
                return AddOverflowLatency();
            case kMipsSubOvf:
                return SubOverflowLatency();
            case kMipsMul:
                return MulLatency(false);
            case kMipsMulHigh:
                return MulhLatency(instr->InputAt(1)->IsRegister());
            case kMipsMulHighU:
                return MulhuLatency(instr->InputAt(1)->IsRegister());
            case kMipsMulOvf:
                return MulOverflowLatency();
            case kMipsMod:
                return ModLatency(instr->InputAt(1)->IsRegister());
            case kMipsModU:
                return ModuLatency(instr->InputAt(1)->IsRegister());
            case kMipsDiv: {
                int latency = DivLatency(instr->InputAt(1)->IsRegister());
                if (IsMipsArchVariant(kMips32r6)) {
                    return latency++;
                } else {
                    return latency + MovzLatency();
                }
            }
            case kMipsDivU: {
                int latency = DivuLatency(instr->InputAt(1)->IsRegister());
                if (IsMipsArchVariant(kMips32r6)) {
                    return latency++;
                } else {
                    return latency + MovzLatency();
                }
            }
            case kMipsClz:
                return ClzLatency();
            case kMipsCtz:
                return CtzLatency();
            case kMipsPopcnt:
                return PopcntLatency();
            case kMipsShlPair: {
                if (instr->InputAt(2)->IsRegister()) {
                    return ShlPairLatency();
                } else {
                    return ShlPairLatency(false);
                }
            }
            case kMipsShrPair: {
                if (instr->InputAt(2)->IsRegister()) {
                    return ShrPairLatency();
                } else {
                    // auto immediate_operand = ImmediateOperand::cast(instr->InputAt(2));
                    // return ShrPairLatency(false, immediate_operand->inline_value());
                    return 1;
                }
            }
            case kMipsSarPair: {
                if (instr->InputAt(2)->IsRegister()) {
                    return SarPairLatency();
                } else {
                    return SarPairLatency(false);
                }
            }
            case kMipsExt:
                return ExtLatency();
            case kMipsIns:
                return InsLatency();
            case kMipsRor:
                return RorLatency(instr->InputAt(1)->IsRegister());
            case kMipsLsa:
                return LsaLatency();
            case kMipsModS:
            case kMipsModD:
                return PrepareCallCFunctionLatency() + MovToFloatParametersLatency() + CallCFunctionLatency() + MovFromFloatResultLatency();
            case kMipsAddPair:
                return AddPairLatency();
            case kMipsSubPair:
                return SubPairLatency();
            case kMipsMulPair:
                return MulPairLatency();
            case kMipsMaddS:
                return MaddSLatency();
            case kMipsMaddD:
                return MaddDLatency();
            case kMipsMsubS:
                return MsubSLatency();
            case kMipsMsubD:
                return MsubDLatency();
            case kMipsNegS:
                return Neg_sLatency();
            case kMipsNegD:
                return Neg_dLatency();
            case kMipsFloat64RoundDown:
            case kMipsFloat64RoundTruncate:
            case kMipsFloat64RoundUp:
            case kMipsFloat64RoundTiesEven:
                return Float64RoundLatency();
            case kMipsFloat32RoundDown:
            case kMipsFloat32RoundTruncate:
            case kMipsFloat32RoundUp:
            case kMipsFloat32RoundTiesEven:
                return Float32RoundLatency();
            case kMipsFloat32Max:
                return Float32MaxLatency();
            case kMipsFloat64Max:
                return Float64MaxLatency();
            case kMipsFloat32Min:
                return Float32MinLatency();
            case kMipsFloat64Min:
                return Float64MinLatency();
            case kMipsCvtSUw:
                return CvtSUwLatency();
            case kMipsCvtDUw:
                return CvtDUwLatency();
            case kMipsFloorWD:
                return FloorWDLatency();
            case kMipsCeilWD:
                return CeilWDLatency();
            case kMipsRoundWD:
                return RoundWDLatency();
            case kMipsTruncWD:
                return Trunc_w_dLatency() + Latency::MFC1;
            case kMipsTruncWS:
                return Latency::TRUNC_W_S + Latency::MFC1 + AdduLatency(false) + SltLatency() + MovnLatency();
            case kMipsTruncUwD:
                return Trunc_uw_dLatency();
            case kMipsTruncUwS:
                return Trunc_uw_sLatency() + AdduLatency(false) + MovzLatency();
            case kMipsFloat64ExtractLowWord32:
                return Latency::MFC1;
            case kMipsFloat64ExtractHighWord32:
                return Mfhc1Latency();
            case kMipsFloat64InsertLowWord32: {
                if (IsFp32Mode()) {
                    return Latency::MTC1;
                } else {
                    return Latency::MFHC1 + Latency::MTC1 + Latency::MTHC1;
                }
            }
            case kMipsFloat64InsertHighWord32:
                return Mthc1Latency();
            case kMipsFloat64SilenceNaN:
                return Latency::SUB_D;
            case kMipsSeb:
                return SebLatency();
            case kMipsSeh:
                return SehLatency();
            case kMipsUlhu:
                return UlhuLatency();
            case kMipsUlh:
                return UlhLatency();
            case kMipsUsh:
                return UshLatency();
            case kMipsUlw:
                return UlwLatency();
            case kMipsUsw:
                return UswLatency();
            case kMipsUlwc1:
                return Ulwc1Latency();
            case kMipsSwc1:
                return MoveLatency(false) + Latency::SWC1; // Estimated max.
            case kMipsUswc1:
                return MoveLatency(false) + Uswc1Latency(); // Estimated max.
            case kMipsLdc1:
                return Ldc1Latency();
            case kMipsUldc1:
                return Uldc1Latency();
            case kMipsSdc1:
                return MoveLatency(false) + Sdc1Latency(); // Estimated max.
            case kMipsUsdc1:
                return MoveLatency(false) + Usdc1Latency(); // Estimated max.
            case kMipsPush: {
                if (instr->InputAt(0)->IsFPRegister()) {
                    auto op = LocationOperand::cast(instr->InputAt(0));
                    switch (op->representation()) {
                    case MachineRepresentation::kFloat32:
                        return Latency::SWC1 + SubuLatency(false);
                        break;
                    case MachineRepresentation::kFloat64:
                        return Sdc1Latency() + SubuLatency(false);
                        break;
                    default: {
                        UNREACHABLE();
                        break;
                    }
                    }
                } else {
                    return PushRegisterLatency();
                }
                break;
            }
            case kMipsPeek: {
                if (instr->OutputAt(0)->IsFPRegister()) {
                    auto op = LocationOperand::cast(instr->OutputAt(0));
                    if (op->representation() == MachineRepresentation::kFloat64) {
                        return Ldc1Latency();
                    } else {
                        return Latency::LWC1;
                    }
                } else {
                    return 1;
                }
                break;
            }
            case kMipsStackClaim:
                return SubuLatency(false);
            case kMipsStoreToStackSlot: {
                if (instr->InputAt(0)->IsFPRegister()) {
                    auto op = LocationOperand::cast(instr->InputAt(0));
                    if (op->representation() == MachineRepresentation::kFloat64) {
                        return Sdc1Latency();
                    } else if (op->representation() == MachineRepresentation::kFloat32) {
                        return Latency::SWC1;
                    } else {
                        return 1; // Estimated value.
                    }
                } else {
                    return 1;
                }
                break;
            }
            case kMipsByteSwap32:
                return ByteSwapSignedLatency();
            case kWord32AtomicLoadInt8:
            case kWord32AtomicLoadUint8:
            case kWord32AtomicLoadInt16:
            case kWord32AtomicLoadUint16:
            case kWord32AtomicLoadWord32:
                return 2;
            case kWord32AtomicStoreWord8:
            case kWord32AtomicStoreWord16:
            case kWord32AtomicStoreWord32:
                return 3;
            case kWord32AtomicExchangeInt8:
                return Word32AtomicExchangeLatency(true, 8);
            case kWord32AtomicExchangeUint8:
                return Word32AtomicExchangeLatency(false, 8);
            case kWord32AtomicExchangeInt16:
                return Word32AtomicExchangeLatency(true, 16);
            case kWord32AtomicExchangeUint16:
                return Word32AtomicExchangeLatency(false, 16);
            case kWord32AtomicExchangeWord32: {
                return 1 + AdduLatency() + Ldc1Latency() + 1 + ScLatency(0) + BranchShortLatency() + 1;
            }
            case kWord32AtomicCompareExchangeInt8:
                return Word32AtomicCompareExchangeLatency(true, 8);
            case kWord32AtomicCompareExchangeUint8:
                return Word32AtomicCompareExchangeLatency(false, 8);
            case kWord32AtomicCompareExchangeInt16:
                return Word32AtomicCompareExchangeLatency(true, 16);
            case kWord32AtomicCompareExchangeUint16:
                return Word32AtomicCompareExchangeLatency(false, 16);
            case kWord32AtomicCompareExchangeWord32:
                return AdduLatency() + 1 + LlLatency(0) + BranchShortLatency() + 1;
            case kMipsTst:
                return AndLatency(instr->InputAt(1)->IsRegister());
            case kMipsCmpS:
                return MoveLatency() + CompareF32Latency();
            case kMipsCmpD:
                return MoveLatency() + CompareF64Latency();
            case kArchNop:
            case kArchThrowTerminator:
            case kMipsCmp:
                return 0;
            case kArchDebugBreak:
            case kArchStackPointer:
            case kArchFramePointer:
            case kArchParentFramePointer:
            case kMipsShl:
            case kMipsShr:
            case kMipsSar:
            case kMipsMov:
            case kMipsMaxS:
            case kMipsMinS:
            case kMipsMaxD:
            case kMipsMinD:
            case kMipsLbu:
            case kMipsLb:
            case kMipsSb:
            case kMipsLhu:
            case kMipsLh:
            case kMipsSh:
            case kMipsLw:
            case kMipsSw:
            case kMipsLwc1:
                return 1;
            case kMipsAddS:
                return Latency::ADD_S;
            case kMipsSubS:
                return Latency::SUB_S;
            case kMipsMulS:
                return Latency::MUL_S;
            case kMipsAbsS:
                return Latency::ABS_S;
            case kMipsAddD:
                return Latency::ADD_D;
            case kMipsSubD:
                return Latency::SUB_D;
            case kMipsAbsD:
                return Latency::ABS_D;
            case kMipsCvtSD:
                return Latency::CVT_S_D;
            case kMipsCvtDS:
                return Latency::CVT_D_S;
            case kMipsMulD:
                return Latency::MUL_D;
            case kMipsFloorWS:
                return Latency::FLOOR_W_S;
            case kMipsCeilWS:
                return Latency::CEIL_W_S;
            case kMipsRoundWS:
                return Latency::ROUND_W_S;
            case kMipsCvtDW:
                return Latency::CVT_D_W;
            case kMipsCvtSW:
                return Latency::CVT_S_W;
            case kMipsDivS:
                return Latency::DIV_S;
            case kMipsSqrtS:
                return Latency::SQRT_S;
            case kMipsDivD:
                return Latency::DIV_D;
            case kMipsSqrtD:
                return Latency::SQRT_D;
            default:
                return 1;
            }
        }

    } // namespace compiler
} // namespace internal
} // namespace v8
